#! /usr/bin/python3

import sys
import os
import signal
from time import sleep

class cpu_info:
	def __init__(self):
		self.utime=0;
		self.ntime=0;
		self.stime=0;
		self.itime=0;
		self.iowtime=0;
		self.irqtime=0;
		self.sirqtime=0;
	def clone(self,cpu):
		self.utime=cpu.utime;
		self.ntime=cpu.ntime;
		self.stime=cpu.stime;
		self.itime=cpu.itime;
		self.iowtime=cpu.iowtime;
		self.irqtime=cpu.irqtime;
		self.sirqtime=cpu.sirqtime;
		

sysCpuMax=20.0;                                #20%
cpuNum=0;                                    #all cpu
flushTime=1;                                 #1s
filePath="./perf.data";                      #./perf.data 
lastTime=10;                                 #10s    

old_cpu=cpu_info()
new_cpu=cpu_info()
usrCpu=0.0
sysCpu=0.0
iowCpu=0.0
irqCpu=0.0

def usage(cmd):
	print(f"Usage: {cmd} [-m maxsys] [-c cpu] [-i interval] [-f outfile] [-l lasttime]\n \
			-m, 设置要监控的sys值，大于这个值运行perf进行数据采集，默认20.\n \
			-c, 设置要监控的cpu，默认是监控整体cpu的sys util.\n \
			-i, 监控sys时，每次扫描的间隔时长，单位秒.\n \
			-f，输出信息的存放文件，默认是./perf.data.\n \
			-l, perf数据采集时长\n")

def handler(signum, frame):
    exit(0)

def read_cpu(cpuNum):
	global old_cpu,new_cpu
	old_cpu.clone(new_cpu)
	with open("/proc/stat", "r",encoding="utf-8") as file:
		for i in range (0,cpuNum+1):
			line=file.readline()
		file.close()
	res=line.replace('  ',' ').split(' ')
	new_cpu.utime=int(res[1],10)
	new_cpu.ntime=int(res[2],10)
	new_cpu.stime=int(res[3],10)
	new_cpu.itime=int(res[4],10)
	new_cpu.iowtime=int(res[5],10)
	new_cpu.irqtime=int(res[6],10)
	new_cpu.sirqtime=int(res[7],10)

def cal_cpu():
	total_delta_time = (new_cpu.utime + new_cpu.ntime + new_cpu.stime + new_cpu.itime \
		+ new_cpu.iowtime + new_cpu.irqtime + new_cpu.sirqtime) \
		- (old_cpu.utime + old_cpu.ntime + old_cpu.stime + old_cpu.itime  \
		+ old_cpu.iowtime + old_cpu.irqtime + old_cpu.sirqtime)
	global usrCpu,sysCpu,iowCpu,irqCpu
	usrCpu=(((new_cpu.utime + new_cpu.ntime) - (old_cpu.utime + old_cpu.ntime)) * 100  / total_delta_time)
	sysCpu=(((new_cpu.stime ) - (old_cpu.stime)) * 100 / total_delta_time);
	iowCpu=(((new_cpu.iowtime) - (old_cpu.iowtime)) * 100 / total_delta_time)
	irqCpu=(((new_cpu.irqtime + new_cpu.sirqtime) - (old_cpu.irqtime + old_cpu.sirqtime)) * 100 / total_delta_time)
	

if __name__=="__main__":
	
	argc=len(sys.argv)
	cpu=os.cpu_count()
	signal.signal(signal.SIGINT, handler)
	
	i=1
	while(i<argc):
		if (sys.argv[i]=="-m"):
			if (i + 1 >= argc): 
				print("Option -m expects an argument.")
				usage(sys.argv[0])
				exit(-1)
			i=i+1
			sysCpuMax = float(sys.argv[i])
			i=i+1
			continue
		if (sys.argv[i]=="-c"):
			if (i + 1 >= argc):
				print("Option -d expects an argument.")
				usage(sys.argv[0])
				exit(-1)
			i=i+1
			cpuNum = int(sys.argv[i],10)
			if(cpuNum>cpu):
				print("cpu number excess {cpu}.")
				usage(sys.argv[0])
				exit(-1)
			i=i+1
			continue
		if (sys.argv[i]=="-i"):
			if (i + 1 >= argc):
				print("Option -s expects an argument.")
				usage(sys.argv[0])
				exit(-1)
			i=i+1
			flushTime = int(sys.argv[i],10)
			i=i+1
			continue
		if (sys.argv[i]=="-f"):
			if (i + 1 >= argc):
				print("Option -f expects an argument.")
				usage(sys.argv[0])
				exit(-1)
			
			i+=1
			filePath=sys.argv[i]
			if not os.access(os.path.dirname(filePath),os.W_OK):
				print(f"wrong filePath {filepath}.")
				usage(sys.argv[0])
				exit(-1)
			i=i+1
			continue
		if (sys.argv[i]=="-l"):
			if (i + 1 >= argc):
				print("Option -l expects an argument.")
				usage(sys.argv[0])
				exit(-1)
			i=i+1
			lastTime=int(sys.argv[i],10)
			i=i+1
			continue;
		if (sys.argv[i]=="-h"):
			usage(sys.argv[0])
			exit(-1)
		print(f"Invalid argument {sys.argv[i]}.")
		usage(sys.argv[0])
		exit(-1)

	read_cpu(cpuNum)
	while(True):
		sleep(flushTime)
		read_cpu(cpuNum)
		cal_cpu()
		print("usrCpu  {:.2f}% sysCpu {:.2f}% iowCpu {:.2f}% irqCpu {:.2f}%".format(usrCpu,sysCpu,iowCpu,irqCpu))
		if(sysCpu>=sysCpuMax):
			line=f"perf record -agq -o {filePath} -- sleep {lastTime}"
			os.system(line)
			break
